<?php
class wiki_model extends Model {

    var $renderedPages;

    function wiki_model()
    {
        // Call the Model constructor
        parent::Model();
        $this->renderedPages=array();
        $this->load->library('wikirenderer');
        $this->load->helper('file');
        $this->load->helper('normalize');
    }


    function getRawAndMeta($pagename)
    {
        $raw =  read_file($this->getPageFilename($pagename));
        $firstline = substr($raw,0,strpos($raw,"\n"));
        $content = substr($raw,strpos($raw,"\n")+1);
        $meta = @unserialize($firstline);
        if ($meta!==false) { $raw=$content;  }
        return array($raw,$meta);    
    }
    
   /**
    * Returns the requested page in html
    * if given, returns a specific "part" (portion of code between [part:name][/part] tags)
    * @param   string  $pagename
    * @param   string  $part 
    * @return  string  xhtml produced
    * @see WikiRenderer.lib.php
    */
    function wiki2html($pagename,$part="") 
    {
        $pagename=$this->basePagename($pagename);
        //check if the page has been rendered during this session
        if (!isset($this->renderedPages[$pagename])) {
            
            list($raw,$meta)=$this->getRawAndMeta($pagename);
            $this->renderedPages['meta_'.$pagename]=$meta;
            
            $content = array();
            $tagStart = 0;
            $cleanraw = "";
            $tagOpen = "[part:";
            $tagClose = "[/part]";
            
            while ($tagStart = strpos($raw, $tagOpen, $tagStart)) {
                //tag is starting and ending
                if ($tagStop = strpos($raw, $tagClose, $tagStart)) {
                    $partName =  substr($raw, $tagStart+strlen($tagOpen), strpos($raw, ']',$tagStart)-$tagStart-strlen($tagOpen));
                    $cleanraw = substr($raw, $tagStart+strlen($tagOpen)+strlen($partName)+1, $tagStop - $tagStart - strlen($tagOpen)-strlen($partName)-1);
                    $tagStart = $tagStop;
                    $content[$partName]=$this->wikirenderer->render(str_replace("\r\n", "\n", $cleanraw));
                } 
            }   
            //renders everything but "part" blocs
            $offset = 0;
            $tagStart = 0;
            $cleanraw = "";
            $tagOpen = "[part";
            $tagClose = "[/part]";
            while ($tagStart = strpos($raw, $tagOpen, $offset)) {
                //tag is starting and ending
                if ($tagStop = strpos($raw, $tagClose, $tagStart)) {
                    $cleanraw .= substr($raw, $offset, $tagStart - $offset);
                    $offset = $tagStop + strlen($tagClose);
                } else {
                    //no ending tag => pbm!
                    return "err";
                }
            }
            if($offset != 0) $cleanraw .= substr($raw, $offset);
            if($cleanraw == "") $cleanraw = $raw;
            $content["main"]= $this->wikirenderer->render(str_replace("\r\n", "\n", $cleanraw));
            $this->renderedPages[$pagename] = $content;
        }
        if ($part!="")
            if (isset($this->renderedPages[$pagename][$part])) 
                return $this->renderedPages[$pagename][$part];
            else
                return "<!-- part does not exists -->";
        else return $this->renderedPages[$pagename];
    }   


    /**
     *
     *Saves and archives the file (preserves existing meta)   
     */              
    function savePage($pagename,$data)
    {
        $this->load->helper("file");
        $pagename=$this->basePagename($pagename);
        $filename=$this->getPageFilename($pagename);
        // archive the previous file i.e. add a date to the end of the filename
        if (file_exists($filename)) {
            $date = date('Y-m-d-H-i', filemtime($filename));
            @copy($filename, str_replace('.dat', ".$date.dat", $filename));
            //if there's n files delete the oldest one
            $versions=$this->getVersions($pagename);
            $last=array_pop($versions);
            if (count($versions)>10)
                unlink($this->getPageFilename($last['name']));
        }
                  // die("whats the matter");
        //keeps existing meta
        if ($prevMeta=$this->readMeta($pagename)!=false) {
            $metaline=serialize($prevMeta)."\n";
        } else {
            $metaline=serialize(array())."\n";
        }
            
        return write_file($filename, $metaline.$data);
    }
    
    
   /**
    * Tests if the data file exists
    * @param   string  $pagename 
    * @return  bool    true if it exists, false otherwise 
    */
    function deletePage($pagename)
    {
        $pagename = $this->basePagename($pagename);
        foreach ($this->i18n->getAllLang() as $name => $lng) {
            $currentDir=DATA_DIR.$lng;
            if ($handle = @opendir($currentDir))
                while ($filename = readdir($handle)) {
                    if (strpos($filename, $pagename) !== false) {
                        rename($currentDir.'/'.$filename,$currentDir.'/trash/'.$filename );
                    }
                }
        }
    }

   /**
    * Tests if the data file exists
    * @param   string  $pagename 
    * @return  bool    true if it exists, false otherwise 
    */
    function pageExists($pageName)
    {
        $filename =  DATA_DIR.$this->i18n->getLangCode().'/'.$pageName.'.dat';
        return file_exists($filename);
    }  
    
   /**
    * Return the filename matching the pagename, no existence verification 
    * @param   string  $pagename 
    * @return  bool    true if it exists, false otherwise 
    */
    function getPageFilename($pageName)
    {
        return DATA_DIR.$this->i18n->getLangCode().'/'.$pageName.'.dat';
    }   
   
   /**
    * Returns the pagename's versions (including the current one)
    * @param   string  $pagename
    * @return  array   list of page's version ("mypage.2007-02-04-20-10", "mypage.2007-02-03-18-28")
    */ 
    function getVersions($pagename)
    {
        $handle = opendir(DATA_DIR.$this->i18n->getLangCode());
        $pagename = $this->basePagename($pagename);
        $i = 0;
        $allpages = array();
        while ($newfile = readdir($handle)) {
            if (strpos($newfile, $pagename) !== false) {
                $name=baseName($newfile,'.dat');
                $date = substr(strstr($name, '.'), 1);
                if ($date != '') {
                    $allpages[$i]['name'] = $name;
                    $allpages[$i]['date'] = $date;
                    $i++;
                }
            }
        }
        @rsort($allpages);
        array_unshift($allpages, array('name' => $pagename, 'date' => 'Last version'));
        return $allpages;
    }

   /**
    * Returns all the pages for a specific language
    * @return  array   list of pages
    */     
    function getAllPages()
    {
        $privatePages = array("trash");
        $handle = opendir(DATA_DIR.$this->i18n->getLangCode());
        $allpages = array();
        while ($newfile = readdir($handle)) {
                $newfile=basename($newfile,".dat");
                if ((strpos($newfile, '.') === false) and (!in_array($newfile, $privatePages)))
                    $allpages[] = $newfile;
        }
        sort($allpages);
        return $allpages;
    }
    
   /**
    * Returns the pagename without the version suffix
    * @param   string  $pagename 
    * @return  string  filtered pagename
    */ 
    function basePagename($pagename)
    {
        if(!(strpos($pagename, '.') === false))
            $pagename = substr($pagename, 0, strpos($pagename, '.'));
        return normalizeStr($pagename);
    }
    
    /**
    * Returns the template and css file to use for this page
    * @param   string  $pagename 
    * @return  array   template & css
    */
    function getStyle($pagename)
    {
        $templates=$this->getStyles();
        $templateName=$this->readMeta($pagename,'template');
        $thisTemplate=isset($templates[$templateName]) ? $templates[$templateName] : $templates['default'];
        return array ('tpl'=>$thisTemplate[1], 'css'=>$thisTemplate[2]);
    }
    

   /**
    * Returns a list of all available "styles" defined in the styles config file
    * a "style" is the combination of a php template and a css file        
    * @return  array   templates & css
    */
    function getStyles()
    {
        $this->config->load('styles');
        $styles = $this->config->item('styles');
        return $styles['wiki'];
    }

   /**
    * Returns a specific meta item for a page  or the array of meta available
    * @param   string  $pagename
    * @param   string  $item              
    * @return  mixed   array or meta item
    */
    function readMeta($pagename,$item="")
    {
        if (!$this->pageExists($pagename)) return false;
        if (!isset($this->renderedPages['meta_'.$pagename])) {
            list($raw,$meta)=$this->getRawAndMeta($pagename);
            $this->renderedPages['meta_'.$pagename] = $meta;
        } 
        if ($item=="")
            return $this->renderedPages['meta_'.$pagename];
        else
            return @$this->renderedPages['meta_'.$pagename][$item];
    }

   /**
    * Writes a meta array to a pagename  
    * @param   string  $pagename
    * @param   array  $meta            
    * @return  array   templates & css
    */    
    function writeMeta($pagename,$meta)
    {
        $pagename = $this->basePagename($pagename);
        if (!$this->pageExists($pagename)) return false;
        list($raw,$currMeta)=$this->getRawAndMeta($pagename);
        $currMeta = ($currMeta!=false) ? array_merge($currMeta,$meta) : $meta;
        return write_file($this->getPageFilename($pagename), serialize($currMeta)."\n".$raw);       
    }

}
?>
